package cn.net.autocode.core.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.http.HttpMethod;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
public class HttpClient {
    private final OkHttpClient webClient;
    private final String baseUrl;

    protected HttpClient(String baseUrl) {
        if (baseUrl.endsWith("/")) {
            this.baseUrl = baseUrl;
        }else{
            this.baseUrl = baseUrl+"/";
        }

        this.webClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(300, TimeUnit.SECONDS)
                .writeTimeout(300, TimeUnit.SECONDS)
                .build();
    }

    protected HttpClient() {
        this.baseUrl = "/";
        this.webClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(300, TimeUnit.SECONDS)
                .writeTimeout(300, TimeUnit.SECONDS)
                .build();
    }

    public <T> T get(String uri, Class<T> returnType){
        return this.get(uri,null,null,returnType);
    }


    public <T> T get(String uri, Map<String,Object> param,Class<T> returnType){
        return this.get(uri,param,null,returnType);
    }

    public <T> T get(String uri, Map<String,Object> param,Map<String,String> header,Class<T> returnType){
        return this.request(uri,param,header,returnType, HttpMethod.GET);
    }

    public <T> T post(String uri, Map<String,Object> param,Class<T> returnType){
        return this.post(uri,param,null,returnType);
    }

    public <T> T post(String uri, Map<String,Object> param,Map<String,String> header,Class<T> returnType){
        return this.request(uri,param,header,returnType,HttpMethod.POST);
    }

    public <T> T postJson(String uri, JSONObject param, Class<T> returnType){
        return this.postJson(uri,param,null,returnType);
    }

    public <T> T postJson(String uri, JSONArray param, Class<T> returnType){
        return this.postJson(uri,param,null,returnType);
    }

    public <T> T postJson(String uri, JSONObject param, Map<String,String> header,Class<T> returnType){
        return this.postJsonCommon(uri,param,header,returnType);
    }

    public <T> T postJson(String uri, JSONArray param, Map<String,String> header,Class<T> returnType){
        return this.postJsonCommon(uri,param,header,returnType);
    }

    private <T> T postJsonCommon(String uri, Object param, Map<String,String> header, Class<T> returnType){

        Request.Builder requestBuilder = new Request.Builder();
        //设置请求地址
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        String url = this.baseUrl + uri;
        requestBuilder.url(url);

        //设置请求参数
        RequestBody body = null;
        if(param instanceof JSONObject json){
            body = RequestBody.create(json.toJSONString(), MediaType.get("application/json; charset=utf-8"));
        }else if(param instanceof JSONArray jsonArray){
            body = RequestBody.create(jsonArray.toJSONString(), MediaType.get("application/json; charset=utf-8"));
        }else{
            throw new RuntimeException("请求参数必须为com.alibaba.fastjson2.JSONObject或com.alibaba.fastjson2.JSONArray格式");
        }
        requestBuilder.post(body);

        //设置header信息
        if(header != null){
            for(Map.Entry<String,String> entry:header.entrySet()){
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        return this.dealResponse(requestBuilder,returnType);
    }


    public <T> T delete(String uri,Class<T> returnType){
        return this.request(uri,null,null,returnType,HttpMethod.DELETE);
    }

    public <T> T delete(String uri, Map<String,Object> param,Class<T> returnType){
        return this.request(uri,param,null,returnType,HttpMethod.DELETE);
    }

    public <T> T delete(String uri, Map<String,Object> param,Map<String,String> header,Class<T> returnType){
        return this.request(uri,param,header,returnType,HttpMethod.DELETE);
    }



    private <T> T request(String uri, Map<String,Object> param,Map<String,String> header,Class<T> returnType,HttpMethod httpMethod){
        Request.Builder requestBuilder = new Request.Builder();
        //设置请求地址
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        String url = this.baseUrl + uri;
        //设置请求参数

        if(httpMethod.name().equals("GET")){
            if(param!=null){
                HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
                for (Map.Entry<String, Object> entry : param.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue().toString();
                    urlBuilder.addQueryParameter(key, URLEncoder.encode(value, StandardCharsets.UTF_8));
                }
                String fullUrl = urlBuilder.build().toString();
                requestBuilder.url(fullUrl);
            }else{
                requestBuilder.url(url);
            }
        }else{
            if(param!=null){
                String json = JSON.toJSONString(param);
                RequestBody body = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
                requestBuilder.url(url).post(body);
            }else{
                requestBuilder.url(url).post(RequestBody.create("{}",MediaType.get("application/json; charset=utf-8")));
            }
        }

        //设置header信息
        if(header != null){
            for(Map.Entry<String,String> entry:header.entrySet()){
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        return this.dealResponse(requestBuilder,returnType);
    }

    public <T> T postFile(String uri, File file, Map<String,Object> param, Class<T> returnType){
        return this.postFile(uri,file,param,null,returnType);
    }


    public <T> T postFile(String uri, File file, Map<String,Object> param,Map<String,String> header, Class<T> returnType){
        Request.Builder requestBuilder = new Request.Builder();
        //设置请求地址
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        String url = this.baseUrl + uri;
        requestBuilder.url(url);
        //设置参数
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        // 添加文本参数
        if (param != null) {
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue().toString());
            }
        }


        // 添加文件
        if (file != null) {
            MediaType fileMediaType = MediaType.parse("application/octet-stream");
            RequestBody fileBody = RequestBody.create(file, fileMediaType);
            multipartBuilder.addFormDataPart("file", file.getName(), fileBody);
        }

        RequestBody requestBody = multipartBuilder.build();
        requestBuilder.post(requestBody);

        //设置header信息
        if(header != null){
            for(Map.Entry<String,String> entry:header.entrySet()){
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        return this.dealResponse(requestBuilder,returnType);
    }

    public String getHtml(String url){
        Request.Builder requestBuilder = new Request.Builder();

        // 创建一个 Request 对象
        Request request = requestBuilder.url(url).build();

        try (Response response = this.webClient.newCall(request).execute()) {
            if (response.isSuccessful() && response.body() != null) {
                String responseBody = response.body().string();
               return responseBody;
            }else{
                int statusCode = response.code();
                String responseBody = response.body() != null ? response.body().string() : "No response body";
                throw new RuntimeException("请求状态："+statusCode+"。<br> 错误信息:"+responseBody);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private <T> T dealResponse(Request.Builder requestBuilder, Class<T> returnType){
        //创建请求实例
        Request request = requestBuilder.build();
        try (Response response = this.webClient.newCall(request).execute()) {
            if (response.isSuccessful() && response.body() != null) {
                String responseBody = response.body().string();
                if(returnType == JSONObject.class){
                    return (T) JSON.parseObject(responseBody);
                }else if(returnType == JSONArray.class){
                    return (T) JSONArray.parseArray(responseBody);
                }else if(returnType == String.class){
                    return (T) responseBody;
                }else{
                    throw new RuntimeException("不支持"+returnType.getName()+"类型的返回值");
                }
            }else{
                int statusCode = response.code();
                String responseBody = response.body() != null ? response.body().string() : "No response body";
                throw new RuntimeException("请求状态："+statusCode+"。<br> 错误信息:"+responseBody);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


}
